﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CYTS.Aoyou.Framework.Core;
using System.ServiceModel;
using Emit = System.Reflection.Emit;
using System.Reflection;

namespace CYTS.Aoyou.Framework.Service
{
    public class ChannelFactoryTypeGenerator<TInterface> : TypeGeneratorBase<TInterface>, ITypeGenerator where TInterface : class
    {
        public ChannelFactoryTypeGenerator()
            : base(typeof(ChannelFactory<TInterface>))
        {
        }

        /// <summary>
        /// 生成类型
        /// </summary>
        /// <returns></returns>
        protected override Type GenerateTypeImplementation()
        {
            Emit.TypeBuilder builder;
            try
            {
                builder = moduleBuilder.DefineType(generatedAssemblyName + "." + generatedClassName, TypeAttributes.Public, baseClassType,
                        new Type[] { typeof(TInterface) });
            }
            catch (Exception ex)
            {
                throw new Exception("未能定义类型 " + generatedClassName + " : " + baseClassType + " , " + typeof(TInterface).Name, ex);
            }
            if (builder == null)
            {
                throw new Exception("未能定义类型 " + generatedClassName + " : " + baseClassType + " , " + typeof(TInterface).Name);
            }

            GenerateConstructor(builder);
            GenerateMethodImpl(builder);

            try
            {
                Type generatedType = builder.CreateType();
                return generatedType;
            }
            catch (Exception ex)
            {
                throw new Exception("未能创建类型 " + generatedClassName + " : " + baseClassType + " , " + typeof(TInterface).Name, ex);
            }
        }

        /// <summary>
        /// 生成类中方法的实现
        /// </summary>
        /// <param name="builder"></param>
        protected override void GenerateMethodImpl(Emit.TypeBuilder builder)
        {
            GenerateServiceMethodImpl(builder, typeof(TInterface));
        }

        /// <summary>
        /// 生成服务方法的实现
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="currentType"></param>
        private void GenerateServiceMethodImpl(Emit.TypeBuilder builder, Type currentType)
        {
            MethodInfo[] methods = currentType.GetMethods();
            foreach (MethodInfo method in methods)
            {
                Type[] parameterTypes = GetParameters(method.GetParameters());
                Emit.MethodBuilder methodBuilder = builder.DefineMethod(method.Name, defaultMethodAttributes, method.ReturnType, parameterTypes);

                methodBuilder.CreateMethodBody(null, 0);
                Emit.ILGenerator iLGenerator = methodBuilder.GetILGenerator();
                iLGenerator.Emit(Emit.OpCodes.Ldarg_0);
                MethodInfo createChannel = baseClassType.GetMethod("CreateChannel", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { }, null);
                iLGenerator.EmitCall(Emit.OpCodes.Call, createChannel, null);
                //
                // 调Open()方法总是报错, 暂时先不调
                //
                //iLGenerator.Emit(OpCodes.Castclass, typeof(ICommunicationObject));
                //MethodInfo methodOpen = typeof(ICommunicationObject).GetMethod("Open", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { }, null);
                //iLGenerator.Emit(OpCodes.Callvirt, methodOpen);
                for (int index = 0; index < parameterTypes.Length; index++)
                {
                    iLGenerator.Emit(Emit.OpCodes.Ldarg, (((short)index) + 1));
                }

                iLGenerator.Emit(Emit.OpCodes.Callvirt, method);
                iLGenerator.Emit(Emit.OpCodes.Ret);
                builder.DefineMethodOverride(methodBuilder, method);
            }
        }

        /// <summary>
        /// 生成构造函数
        /// </summary>
        /// <param name="builder"></param>
        protected override void GenerateConstructor(Emit.TypeBuilder builder)
        {
            if (builder.BaseType.Name.StartsWith("ChannelFactory") == true && builder.BaseType.Assembly.FullName.StartsWith("System.ServiceModel") == true)
            {
                Type[] constructorParameters = new[] { typeof(System.ServiceModel.Channels.Binding), typeof(EndpointAddress) };
                Emit.ConstructorBuilder constructorBuilder = builder.DefineConstructor(MethodAttributes.Public | MethodAttributes.RTSpecialName, CallingConventions.Standard, constructorParameters);
                Emit.ILGenerator iLGenerator = constructorBuilder.GetILGenerator();
                iLGenerator.Emit(Emit.OpCodes.Ldarg_0);
                iLGenerator.Emit(Emit.OpCodes.Ldarg_1);
                iLGenerator.Emit(Emit.OpCodes.Ldarg_2);
                ConstructorInfo originalConstructor = baseClassType.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, constructorParameters, null);
                iLGenerator.Emit(Emit.OpCodes.Call, originalConstructor);
                iLGenerator.Emit(Emit.OpCodes.Ret);
            }
        }
    }
}
